perm filename STRUCT.MSS[WHT,LSP] blob sn#754074 filedate 1984-05-12 generic text, type T, neo UTF8
@Part[Struct, Root = "CLM.MSS"]
@Comment{Chapter of Common Lisp Manual.  Copyright 1984 Guy L. Steele Jr.⎇

@MyChapter[Structures]

@clisp provides a facility for creating named record structures
with named components.  In effect, the user can define a new data type;
every data structure of that type has components with specified names.
Constructor, access, and assignment constructs are automatically
defined when the data type is defined.

This chapter is divided into two parts.  The first part discusses
the basics of the structure facility, which is very simple and allows
the user to take advantage of the type-checking, modularity, and
convenience of user-defined record data types.  The second part,
beginning with section @ref[Defstruct-Hairy-Stuff],
discusses a number of specialized features of the facility that
have advanced applications.  These features are completely optional,
and you needn't even know they exist in order to take
advantage of the basics.

@Section[Introduction to Structures]
@label[DEFSTRUCT-INTRO-SECTION]

The structure facility is embodied in the @f[defstruct] macro,
which allows the user to create and use
aggregate data types with named elements.  These are like
``structures'' in @pl1, or ``records'' in @pascal.

As an example, assume you are writing a @xlisp
program that deals with space ships in a two-dimensional plane.
In your program, you need to
represent a space ship by a @xlisp object of some kind.  The interesting
things about a space ship, as far as your program is concerned, are
its position (represented as @i[x] and @i[y] coordinates),
velocity (represented as components along the @i[x] and @i[y] axes), and mass.

A ship might therefore be represented as a record structure with five
components: @i[x]-position, @i[y]-position, @i[x]-velocity, @i[y]-velocity, and mass.
This structure could in turn be implemented as a @xlisp object in a
number of ways.  It could be a list of five elements; the @i[x]-position
could be the @i[car], the @i[y]-position the @i[cadr], and so on.  Equally
well it could be a vector of five elements: the @i[x]-position could be
element 0, the @i[y]-position element 1, and so on.  The problem with either
of these representations is that the components occupy places in the
object that are quite arbitrary and hard to remember.  Someone looking at
@f[(cadddr@ ship1)] or @f[(aref@ ship1@ 3)] in a piece of code might
find it difficult to determine that this is accessing the @i[y]-velocity
component of @f[ship1].  Moreover, if the representation of a ship should
have to be changed, it would be very difficult to find all the places
in the code to be changed to match (not all occurrences of @f[cadddr]
are intended to extract the @i[y]-velocity from a ship).

Ideally components of record structures should have names.  One would
like to write something like
@f[(ship-y-velocity ship1)] instead of @f[(cadddr ship1)].
One would also like a more mnemonic way to create a ship than this:
@Lisp
(list 0 0 0 0 0)
@Endlisp
Indeed, one would like @f[ship] to be a new data type, just like other
@xlisp data types, that one could test with @Funref[typep], for example.
The @f[defstruct] facility provides all of this.

@f[defstruct] itself is a macro that defines a structure.  For the
space ship example, one might define the structure by saying:
@Lisp
(defstruct ship
  x-position
  y-position
  x-velocity
  y-velocity
  mass)
@Endlisp
This declares that every @f[ship] is an object with five named components.
The evaluation of this form does several things:
@Begin[Itemize]
It defines @f[ship-x-position] to be a function
of one argument, a ship, that returns the @i[x]-position
of the ship; @f[ship-y-position]
and the other components are given similar function definitions.
These functions are called the @Def[access functions], as they
are used to access elements of the structure.

The symbol @f[ship] becomes the name of a data type of which instances
of ships are elements.  This name becomes acceptable to @Funref[typep],
for example; @f[(typep x 'ship)] is true if @f[x] is a ship
and false if @f[x] is any object other than a ship.
Moreover, all ships are instances of the type @f[structure], because
@f[ship] is a subtype of @f[structure].

A function named @f[ship-p] of one argument is defined; it is a predicate
that is true if its argument is a ship and is false otherwise.

@Begin[Multiple]
A function called @f[make-ship] is defined that, when invoked,
will create a data structure with five components, suitable for use with
the access functions.  Thus executing
@Lisp
(setq ship2 (make-ship))
@Endlisp
sets @f[ship2] to a newly created @f[ship] object.
One can specify the initial values of any desired component in the call
to @f[make-ship] by using keyword arguments in this way:
@Lisp
(setq ship2 (make-ship @Kwd[mass] *default-ship-mass*
		       @Kwd[x-position] 0
		       @Kwd[y-position] 0))
@Endlisp
This constructs a new ship and initializes three of its components.
This function is called the @Def[constructor function]
because it constructs a new structure.
@End[Multiple]

@Begin[Multiple]
The @f[#S] syntax can be used to read instances of @f[ship]
structures, and a printer function is provided for printing
out ship structures.  For example, the value of the
variable @f[ship2] shown above might be printed as
@lisp
#S(ship  x-position 0  y-position 0  x-velocity nil
	 y-velocity nil  mass 170000.0)
@endlisp
@End[Multiple]

@Begin[Multiple]
A function called @f[copy-ship] of one argument
is defined that, when given a @f[ship] object,
will create a new @f[ship] object that is a copy of the given one.
This function is called the @Def[copier function].
@End[Multiple]

@Begin[Multiple]
One may use @f[setf] to alter the components of a @f[ship]:
@Lisp
(setf (ship-x-position ship2) 100)
@Endlisp
This alters the @i[x]-position of @i[ship2] to be @f[100].
This works because @f[defstruct] behaves as if
it generates an appropriate @Macref[defsetf]
form for each access function.
@End[Multiple]
@End[Itemize]

This simple example illustrates the power of @f[defstruct] to provide
abstract record structures in a convenient manner.
@f[defstruct] has many other features as well for specialized purposes.

@Section[How to Use Defstruct]

All structures are defined through the @f[defstruct] construct.

@Defmac[Fun {defstruct⎇, Args {@i[name-and-options] @mopt<@i[doc-string]> @Mplus<@i[slot-description]>⎇]
This defines a record-structure data type.
A general call to @f[defstruct] looks like this:
@Lisp
(defstruct (@i[name] @i[option-1] @i[option-2] ...)
	   @i[doc-string]
	   @i[slot-description-1]
	   @i[slot-description-2]
	   ...)
@Endlisp
The @i[name] must be a symbol; it becomes the name of a new data type
consisting of all instances of the structure.
The function @Funref[typep] will accept and use this name
as appropriate.  The @i[name] is returned as the value of the @i[defstruct]
form.

Usually no options are needed at all.
If no options are specified, then one may write simply @i[name] instead
of @f[(@i[name])] after the word @f[defstruct].  The syntax of options
and the options provided are discussed in section @ref[DEFSTRUCT-OPTIONS].

If the optional documentation string @i[doc-string] is present,
then it is attached to the @i[name]
as a documentation string of type @f[structure]; see @Funref[documentation].

Each @i[slot-description-j] is of the form
@Lisp
(@i[slot-name] @i[default-init]
     @i[slot-option-name-1] @i[slot-option-value-1]
     @i[slot-option-name-2] @i[slot-option-value-2]
     ...)
@Endlisp
Each @i[slot-name] must be a symbol; an access function is defined
for each slot. If no options and no @i[default-init] are specified,
then one may write simply @i[slot-name] instead of @f[(@i[slot-name])]
as the slot description.  The @i[default-init] is a form that is
evaluated @i[each time] a structure is to be constructed; the value
is used as the initial value of the slot.  If no @i[default-init]
is specified, then the initial contents of the slot are undefined
and implementation-dependent.  The available slot-options are
described in section @Ref[Defstruct-Slot-Options].
@Incompatibility{Slot-options are not currently provided
in @lmlisp, but this is an upward-compatible extension.⎇

@f[defstruct] not only defines an access function for each slot, but also
arranges for @f[setf] to work properly on such access functions,
defines a predicate named @f[@i[name]-p],
defines a constructor function named @f[make-@i[name]],
and defines a copier function named @f[copy-@i[name]].
All names of automatically created functions are interned
in whatever package is current at the time the @f[defstruct]
form is processed (see @Varref[package]).
Also, all such functions may be declared @f[inline]
at the discretion of the implementation to improve efficiency;
if you do not want some function declared @f[inline],
follow the @f[defstruct] form with a @f[notinline] declaration
to override any automatic @f[inline] declaration.
@Enddefmac

@Section[Using the Automatically Defined Constructor Function]

After you have defined a new structure with @f[defstruct], you can
create instances of this structure by using the constructor function.
By default, @f[defstruct] defines this function automatically.
For a structure named @f[foo], the constructor function is normally
named @f[make-foo];
you can specify a different name
by giving it as the argument to the
@Kwdref[F {defstruct⎇, K {constructor⎇] option, or specify that you don't
want a normal
constructor function at all by using @false as the argument
(in which case one or more ``by-position'' constructors should be
requested; see section @ref[DEFSTRUCT-CONSTRUCTOR-SYNTAX].

A call to a constructor function, in general, has the form
@Lisp
(@i[name-of-constructor-function]
        @i[slot-keyword-1] @i[form-1]
        @i[slot-keyword-2] @i[form-2]
        ...)
@Endlisp
All arguments are keyword arguments.  Each @i[slot-keyword] should be a
keyword whose name matches the name of a slot of the structure
(@f[defstruct] determines the possible keywords simply by interning each
slot-name in the keyword package).  All the @i[keywords] and @i[forms]
are evaluated.  In short, it is just as if the constructor function
took all its arguments as @key parameters.  For example, the
@f[ship] structure shown in section @ref[DEFSTRUCT-INTRO-SECTION]
has a constructor function that takes arguments roughly as if its definition
were
@lisp
(defun make-ship (&key x-position y-position
		       x-velocity y-velocity mass)
  ...)
@endlisp

@Label{defstruct-initialization⎇
If @i[slot-keyword-j] names a slot, then that element of
the created structure will be initialized to the value of @i[form-j].
If no pair @i[slot-keyword-j] and @i[form-j]
is present for a given slot, then the slot will be
initialized by evaluating the @i[default-init] form specified
for that slot in the call to @f[defstruct].
(In other words, the initialization specified in the @f[defstruct]
defers to any specified in a call to the constructor function.)
If the default initialization form is used, it is evaluated
at construction time, but
in the lexical environment of the @f[defstruct] form in which it appeared.
If the @f[defstruct] itself also did not
specify any initialization, the element's initial value is undefined.
You should always specify the initialization, either in the @f[defstruct]
or in the call to the constructor function,
if you care about the initial value of the slot.

Each initialization form specified for a @f[defstruct] component,
when used by the constructor function for an otherwise unspecified
component, is re-evaluated on every call to the
constructor function.  It is as if the initialization forms were
used as @i[init] forms for the keyword parameters of the
constructor function.
For example, if the form @f[(gensym)]
were used as an initialization form,
either in the constructor-function call or as the default initialization form
in the @f[defstruct] form,
then every call to the constructor
function would call @f[gensym] once to generate a new symbol.

This concludes the basic description of @f[defstruct].
The sections that follow describe more advanced features.

@Section[Defstruct Slot-Options]
@Label[Defstruct-Slot-Options]

Each @i[slot-description] in a @f[defstruct] form may specify one or more
slot-options.  A slot-option consists of a pair of a keyword and
a value (which is not a form to be evaluated, but the value itself).
For example:
@lisp
(defstruct ship
  (x-position 0.0 @Kwd[type] short-float)
  (y-position 0.0 @Kwd[type] short-float)
  (x-velocity 0.0 @Kwd[type] short-float)
  (y-velocity 0.0 @Kwd[type] short-float)
  (mass *default-ship-mass* @Kwd[type] short-float @Kwd[read-only] t))
@Endlisp
This specifies that each slot will always contain a
short-format floating-point number,
and that the last slot may not be altered once a ship is constructed.

The available slot-options are:
@Randomkeywordlist{@f[defstruct] slot-descriptions⎇
@Randomkeyword[type]
The option @f[@Kwd[type] @i[type]] specifies that the contents of the
slot will always be of the specified data type.  This is entirely
analogous to the declaration of a variable or function; indeed, it
effectively declares the result type of the access function.  An
implementation may or may not choose to check the type of the new object
when initializing or assigning to a slot.
Note that the argument form @i[type] is not evaluated;
it must be a valid type specifier.
@Endrandomkeyword

@Randomkeyword[read-only]
The option @f[@Kwd[read-only] @i[x]], where @i[x] is not @false,
specifies that this slot may not be
altered; it will always contain the value specified at construction time.
@Macref[setf] will not accept the access function for this slot.
If @i[x] is @false, this slot-option has no effect.
Note that the argument form @i[x] is not evaluated.
@Endrandomkeyword
@Endrandomkeywordlist
Note that it is impossible to specify a slot-option unless
a default value is specified first.

@Section[Defstruct Options]
@label[DEFSTRUCT-OPTIONS]
@Label[Defstruct-Hairy-Stuff]

The preceding description of @f[defstruct] is all that the average
user will need (or want) to know in order to use structures.
The remainder of this chapter discusses more complex features of
the @f[defstruct] facility.

This section explains each of the options that can be given to @f[defstruct].
A @f[defstruct] option may be either a keyword
or a list of a keyword and arguments for that keyword.
(Note that the syntax for @f[defstruct] options differs from
the pair syntax used for slot-options.  No part of any of these options
is evaluated.)

@Keywordlist[defstruct]
@Keyword[conc-name]
This provides for automatic prefixing of names of access functions.
It is conventional to begin the names of all the access functions of
a structure with a specific prefix,
the name of the structure followed by a hyphen.
This is the default behavior.

The argument to the @Kwd[conc-name] option specifies an alternate
prefix to be used.  (If a hyphen is to be used as a separator,
it must be specified as part of the prefix.)
If @false is specified as an argument, then @i[no] prefix is used;
then the names of the access functions
are the same as the slot names, and it is up to the user
to name the slots reasonably.

Note that no matter what is specified for @Kwd[conc-name],
with a constructor function one uses
slot keywords that match the slot names, with no prefix attached.
On the other hand, one uses the access-function name
when using @f[setf].  Here is an example:
@Lisp
(defstruct door knob-color width material)
(setq my-door (make-door :knob-color 'red :width 5.0))
(door-width my-door) @EV 5.0
(setf (door-width my-door) 43.7)
(door-width my-door) @EV 43.7
@Endlisp
@Endkeyword

@Keyword[constructor]
This option takes one argument, a symbol,
which specifies the name of the constructor
function.  If the argument is not provided or if the option itself is not
provided, the name of the constructor is produced by concatenating the
string @f["MAKE-"] and the name of the structure, putting the name
in whatever package is current at the time the @f[defstruct]
form is processed (see @Varref[package]).
If the argument is
provided and is @false, no constructor function is defined.

This option actually has a more general syntax that is explained
in section @ref[DEFSTRUCT-CONSTRUCTOR-SYNTAX].
@EndKeyword

@Keyword[copier]
This option takes one argument, a symbol,
which specifies the name of the copier
function.  If the argument is not provided or if the option itself is not
provided, the name of the copier is produced by concatenating the
string @f["COPY-"] and the name of the structure, putting the name
in whatever package is current at the time the @f[defstruct]
form is processed (see @Varref[package]).
If the argument is provided and is @false, no copier function is defined.

The automatically defined copier function simply makes a new structure
and transfers all components verbatim from the argument into the
newly created structure.  No attempt is made to make copies
of the components.  Corresponding components of the old and
new structures will therefore be @f[eql].
@Endkeyword

@Keyword[predicate]
This option takes one argument, which specifies the name of the type predicate.
If the argument is not provided or if the option itself is not
provided, the name of the predicate is made by concatenating the
name of the structure to the string @f["-P"], putting the name
in whatever package is current at the time the @f[defstruct]
form is processed (see @Varref[package]).
If the argument is
provided and is @false, no predicate is defined.  A predicate can be defined
only if the structure is ``named'';
if the @Kwdref[F {defstruct⎇, K {type⎇] option is specified
and the @Kwdref[F {defstruct⎇, K {named⎇] option is
not specified, then the @Kwd[predicate] option must either be unspecified
or have the value @false.
@Endkeyword

@Keyword[include]
This option is used for building a new structure definition as
an extension of an old structure definition.  As an example,
suppose you have a structure called @f[person] that looks like this:
@Lisp
(defstruct person name age sex)
@Endlisp
Now suppose you want to make a new structure to represent an astronaut.
Since astronauts are people too, you would like them to also have the
attributes of name, age, and sex, and you would like @xlisp functions
that operate on @f[person] structures to operate just as well on
@f[astronaut] structures.  You can do this by defining @f[astronaut]
with the @Kwd[include] option, as follows:

@Lisp
(defstruct (astronaut (:include person)
		      (:conc-name astro-))
   helmet-size
   (favorite-beverage 'tang))
@Endlisp

The @Kwd[include] option causes the structure being defined
to have the same slots as the included structure.
This is done in such a way
that the access functions for the included
structure will also work on the structure being defined.
In this example, an
@f[astronaut] will therefore have five slots: the three defined in
@f[person] and the two defined in @f[astronaut]
itself.  The access functions defined by the @f[person] structure
can be applied to instances of the @f[astronaut] structure, and they
will work correctly.
Moreover, @f[astronaut] will have its own access functions for
components defined by the @f[person] structure.
The following examples illustrate how you can
use @f[astronaut] structures:

@Lisp
(setq x (make-astronaut :name 'buzz
			:age 45.
			:sex t
			:helmet-size 17.5))

(person-name x) @EV buzz
(astro-name x) @EV buzz
(astro-favorite-beverage x) @EV tang
@Endlisp
The difference between the access functions @f[person-name] and @f[astro-name]
is that @f[person-name] may be correctly applied to any @f[person],
including an @f[astronaut], while @f[astro-name] may be correctly
applied only to an @f[astronaut].  (An implementation may or may not
check for incorrect use of access functions.)

At most one @Kwd[include] option may be specified in a single
@f[defstruct] form.
The argument to the @Kwd[include] option is required and must be the
name of some previously defined structure.  If the structure being
defined has no @Kwd[type] option, then the included structure must
also have had no @Kwd[type] option specified for it.
If the structure being defined has a @Kwd[type] option,
then the included structure must have been declared with a @Kwd[type]
option specifying the same representation type.

If no @Kwd[type] option is involved, then
the structure name of the including structure definition
becomes the name of a data type, of course, and therefore
a valid type specifier recognizable by @Funref[typep]; moreover, it becomes
a subtype of the included structure.  In the above example,
@f[astronaut] is a subtype of @f[person]; hence
@Lisp
(typep (make-astronaut) 'person)
@Endlisp
is true, indicating that all operations on persons will also
work on astronauts.

The following is an advanced feature of the @Kwd[include] option.
Sometimes, when one structure includes another, the default values or
slot-options for the slots that came from the included structure are not
what you want.  The new structure can specify default values or
slot-options for the included slots different from those the included
structure specifies, by giving the @Kwd[include] option as:
@Lisp
(:include @i[name] @i[slot-description-1] @i[slot-description-2] ...)
@Endlisp
Each @i[slot-description-j] must have a @i[slot-name] or @i[slot-keyword] that is the same
as that of some slot in the included structure.
If @i[slot-description-j] has no @i[default-init],
then in the new structure the slot will have no initial
value.  Otherwise its initial value form will be replaced by
the @i[default-init] in @i[slot-description-j].
A normally writable slot may be made read-only.
If a slot is read-only in the included structure, then it
must also be so in the including structure.
If a type is specified for a slot, it must be the same as, or a subtype of, the
type specified in the included structure.  If it is a strict subtype,
the implementation may or may not choose to error-check assignments.

For example, if we had wanted to define @f[astronaut] so that the
default age for an astronaut is @f[45], then we could have said:
@Lisp
(defstruct (astronaut (:include person (age 45)))
   helmet-size
   (favorite-beverage 'tang))
@Endlisp
@Endkeyword

@Keyword[print-function]
This option may be used only if the @Kwdref[F {defstruct⎇, K {type⎇]
option is not specified.
The argument to the @Kwd[print-function] option
should be a function of three arguments,
in a form acceptable to the @Specref[function] special form,
to be used to print structures of this type.
When a structure of this type is to be printed, the function
is called on three arguments:
the structure to be printed, a stream to print to,
and an integer indicating the current depth (to be compared against
@Varref[print-level]).
The printing function should observe the values of
such printer-control variables as @Varref[print-escape]
and @Varref[print-pretty].

If the @Kwd[print-function] option is not specified and the @Kwd[type]
option also not specified, then a default printing function is
provided for the structure that will print out all its slots
using @f[#S] syntax (see section @ref[SHARP-SIGN-MACRO-CHARACTER-SECTION]).
@Endkeyword

@Keyword[type]
The @Kwd[type] option explicitly specifies the representation to be used for
the structure.  It takes one argument, which must
be one of the types enumerated below.

Specifying this option has the effect of forcing
a specific representation and of forcing the components to be
stored in the order specified in the @f[defstruct] form
in corresponding successive elements of the specified representation.
It also @i[prevents] the structure name from becoming a valid
type specifier recognizable by @Funref[typep].  See section
@ref[EXPLICIT-TYPE-STRUCTURES] for details.

Normally this option is not specified, in which case the structure
is represented in an implementation-dependent manner.
@Subkeywordlist[type]
@PseudoSubkeyword{@f[vector]⎇
This produces the same result as specifying @f[(vector t)].
The structure is represented
as a general vector, storing components as vector elements.
The first component is vector
element 1 if the structure is @Kwd[named], and element 0 otherwise.
@Endsubkeyword

@PseudoSubKeyword{@f[(vector @i[element-type])]⎇
The structure is represented as a (possibly specialized) vector, storing
components as vector elements.  Every component must be of a type that can be
stored in a vector of the type specified.  The first component is vector
element 1 if the structure is @Kwd[named], and element 0 otherwise.
The structure may be @Kwd[named] only if the type @f[symbol] is a subtype of
the specified @f[element-type].
@EndSubKeyword

@pseudoSubkeyword{@f[list]⎇
The structure is represented as a list.
The first component is the @i[cadr]
if the structure is @Kwd[named], and the @i[car] if
it is @Kwd[unnamed].
@EndSubKeyword
@EndSubKeywordList
@EndKeyword

@Keyword[named]
The @Kwd[named] option specifies that the structure is ``named''; this
option takes no argument.  If no @Kwd[type] option is specified,
then the structure is always named; so this option is useful only in
conjunction with the @Kwd[type] option.  See section
@ref[EXPLICIT-TYPE-STRUCTURES] for a further description of this option.
@Endkeyword

@Keyword[initial-offset]
This allows you to tell @f[defstruct] to skip over a certain
number of slots before it starts allocating the slots described in the
body.  This option requires an argument,
a non-negative integer,
which is the number of slots you want @f[defstruct] to skip.
The @Kwd[initial-offset] option may be used only if the
@Kwd[type] option is also specified.
See section @ref[DEFSTRUCT-INITIAL-OFFSET] for a further description
of this option.
@EndKeyword
@EndKeywordList


@Section[By-position Constructor Functions]
@label[DEFSTRUCT-CONSTRUCTOR-SYNTAX]

If the @Kwdref[F {defstruct⎇, K {constructor⎇] option is given as
@f[(@Kwd[constructor] @i[name] @i[arglist])], then instead of making a keyword
driven constructor function, @f[defstruct] defines a ``positional'' constructor function,
taking arguments whose meaning is determined by the argument's position
rather than by a keyword.
The @i[arglist] is used to describe what the arguments to the
constructor will be.  In the simplest case something like
@f[(@Kwd[constructor] make-foo (a b c))] defines @f[make-foo] to be
a three-argument constructor function whose arguments are used to initialize the
slots named @f[a], @f[b], and @f[c].

In addition, the keywords @f[&optional], @f[&rest], and @f[&aux] are
recognized in the argument list.  They work in the way you might expect,
but there are a few fine points worthy of explanation.
Consider this example:
@lisp
(@Kwd[constructor] create-foo
	(a &optional b (c 'sea) &rest d &aux e (f 'eff)))
@Endlisp
This defines @f[create-foo] to be a constructor of one or more arguments.
The first argument is used to initialize the @f[a] slot.  The second
argument is used to initialize the @f[b] slot.  If there isn't any
second argument, then the default value given in the body of the
@f[defstruct] (if given) is used instead.  The third argument is used to
initialize the @f[c] slot.  If there isn't any third argument, then the
symbol @f[sea] is used instead.  Any arguments following the third
argument are collected into a list and used to initialize the @f[d]
slot.  If there are three or fewer arguments, then @false is placed in
the @f[d] slot.  The @f[e] slot @i[is not initialized]; its initial
value is undefined.  Finally, the @f[f] slot is initialized to contain
the symbol @f[eff].

The actions taken in the @f[b] and @f[e] cases were carefully
chosen to allow the user to specify all possible behaviors.  Note that
the @aux ``variables'' can be used to completely override the default
initializations given in the body.

With this definition, one can write
@Lisp
(create-foo 1 2)
@Endlisp
instead of
@Lisp
(make-foo @Kwd[a] 1 @Kwd[b] 2)
@Endlisp
and of course @f[create-foo] provides defaulting different
from that of @f[make-foo].

It is permissible to use the
@Kwd[constructor] option more than once, so that you can define several
different constructor functions, each taking different parameters.

Because a constructor of this type operates By Order of Arguments,
it is sometimes known as a BOA constructor.


@Section[Structures of Explicitly Specified Representational Type]
@Label[EXPLICIT-TYPE-STRUCTURES]

Sometimes it is important to have explicit control
over the representation of a structure.  The @Kwdref[F {defstruct⎇, K {type⎇]
option allows one to specify that a structure must be implemented
in a particular way, using a list or a specific kind of vector,
and to specify the exact allocation of structure slots to
components of the representation.
A structure may also be ``unnamed'' or ``named,'' according to whether
the structure name is stored in (and thus recoverable from) the structure.

@Subsection[Unnamed Structures]

Sometimes a particular data representation is imposed by external requirements,
and yet it is desirable to document the data format as a @f[defstruct]-style
structure.  For example, consider expressions built up from numbers,
symbols, and binary operations such as @f[+] and @f[*].  An operation
might be represented as it is in @xlisp, as a list of the operator
and the two operands.  This fact can be expressed succinctly with @f[defstruct]
in this manner:
@lisp
(defstruct (binop (:type list))
  (operator '? :type symbol)
  operand-1
  operand-2)
@endlisp
This will define a constructor function @f[make-binop] and three
selector functions, namely @f[binop-operator], @f[binop-operand-1],
and @f[binop-operand-2].  (It will @i[not], however, define a predicate
@f[binop-p], for reasons explained below.)

The effect of @f[make-binop] is simply to construct a list of length three:
@lisp
(make-binop :operator '+ :operand-1 'x :operand-2 5)
   @EV (+ x 5)
(make-binop :operand-2 4 :operator '*)
   @EV (* @nil 4)
@endlisp
It is just like the function @f[list] except that it takes
keyword arguments and performs slot defaulting appropriate to the @f[binop]
conceptual data type.  Similarly, the selector functions
@f[binop-operator], @f[binop-operand-1],
and @f[binop-operand-2] are essentially equivalent to @f[car],
@f[cadr], and @f[caddr], respectively.  (They might not be
completely equivalent because,
for example, an implementation would be justified in adding error-checking
code to ensure that the argument to each selector function is a length-3
list.)

We speak of @f[binop] as being a ``conceptual'' data type because @f[binop]
is not made a part of the @clisp type system.  The predicate
@Funref[typep] will not recognize @f[binop] as a type specifier, and @f[type-of]
will return @f[list] when given a @f[binop] structure.  Indeed, there is
no way to distinguish a data structure constructed by @f[make-binop]
from any other list that happens to have the correct structure.

There is not even any way to recover the structure name @f[binop] from
a structure created by @f[make-binop].  This can be done, however,
if the structure is ``named.''

@Subsection[Named Structures]

A ``named'' structure has the property that, given an instance of the
structure, the structure name (that names the type) can be reliably
recovered.  For structures defined
with no @Kwd[type] option, the structure name actually becomes part
of the @clisp data-type system.  The function @Funref[type-of],
when applied to such a structure, will return the structure name
as the type of the object; the predicate @Funref[typep] will recognize
the structure name as a valid type specifier.

For structures defined with a @Kwd[type] option, @f[type-of] will
return a type specifier such as @f[list] or @f[(vector t)],
depending on the type specified to the @Kwd[type] option.
The structure name does not become a valid type specifier.
However,
if the @Kwd[named] option is also specified, then the first component
of the structure (as created by a @f[defstruct] constructor function)
will always contain the structure name.  This allows the structure name
to be recovered from an instance of the structure and allows a reasonable
predicate for the conceptual type to be defined:
the automatically defined
@f[@i[name]-p] predicate for the structure operates by first
checking that its argument is of the proper type (@f[list], @f[(vector t)],
or whatever) and then checking whether the first component contains
the appropriate type name.

Consider the @f[binop] example shown above, modified only to
include the @Kwd[named] option:
@lisp
(defstruct (binop (:type list) :named)
  (operator '? :type symbol)
  operand-1
  operand-2)
@endlisp
As before, this will define a constructor function @f[make-binop] and three
selector functions @f[binop-operator], @f[binop-operand-1],
and @f[binop-operand-2].  It will also define a predicate @f[binop-p].

The effect of @f[make-binop] is now to construct a list of length four:
@lisp
(make-binop :operator '+ :operand-1 'x :operand-2 5)
   @EV (binop + x 5)
(make-binop :operand-2 4 :operator '*)
   @EV (binop * @nil 4)
@endlisp
The structure has the same layout as before except that the structure name
@f[binop] is included as the first list element.
The selector functions
@f[binop-operator], @f[binop-operand-1],
and @f[binop-operand-2] are essentially equivalent to @f[cadr],
@f[caddr], and @f[cadddr], respectively.
The predicate @f[binop-p] is more or less equivalent to this
definition:
@lisp
(defun binop-p (x)
  (and (consp x) (eq (car x) 'binop)))
@endlisp
The name @f[binop] is still not a valid type specifier recognizable
to @f[typep], but at least there is a way of distinguishing @f[binop]
structures from other similarly defined structures.

@Subsection[Other Aspects of Explicitly Specified Structures]
@label[DEFSTRUCT-INITIAL-OFFSET]

The @Kwdref[F {defstruct⎇, K {initial-offset⎇] option allows one
to specify that slots be allocated beginning at a representational
element other than the first.  For example, the form
@lisp
(defstruct (binop (:type list) (:initial-offset 2))
  (operator '? :type symbol)
  operand-1
  operand-2)
@endlisp
would result in the following behavior for @f[make-binop]:
@lisp
(make-binop :operator '+ :operand-1 'x :operand-2 5)
   @EV (nil nil + x 5)
(make-binop :operand-2 4 :operator '*)
   @EV (nil nil * @nil 4)
@endlisp
The selector functions
@f[binop-operator], @f[binop-operand-1],
and @f[binop-operand-2] would be essentially equivalent to @f[caddr],
@f[cadddr], and @f[car] of @f[cddddr], respectively.
Similarly, the form
@lisp
(defstruct (binop (:type list) :named (:initial-offset 2))
  (operator '? :type symbol)
  operand-1
  operand-2)
@endlisp
would result in the following behavior for @f[make-binop]:
@lisp
(make-binop :operator '+ :operand-1 'x :operand-2 5)
   @EV (nil nil binop + x 5)
(make-binop :operand-2 4 :operator '*)
   @EV (nil nil binop * @nil 4)
@endlisp

If the @Kwdref[F {defstruct⎇, K {include⎇] is used with the @Kwd[type]
option, then the effect is first to skip over as many representation
elements as needed to represent the included structure, then to
skip over any additional elements specified by the @Kwd[initial-offset]
option, and then to begin allocation of elements from that point.
For example:
@lisp
(defstruct (binop (:type list) :named (:initial-offset 2))
  (operator '? :type symbol)
  operand-1
  operand-2)

(defstruct (annotated-binop (:type list)
			    (:initial-offset 3)
			    (:include binop))
  commutative associative identity)

(make-annotated-binop :operator '*
		      :operand-1 'x
		      :operand-2 5
		      :commutative t
		      :associative t
		      :identity 1)
   @EV (nil nil binop * x 5 nil nil nil t t 1)
@endlisp
The first two @nil elements stem from the @Kwd[initial-offset] of @f[2]
in the definition of @f[binop].  The next four elements contain the
structure name and three slots for @f[binop].  The next three @nil elements
stem from the @Kwd[initial-offset] of @f[3] in the definition of
@f[annotated-binop].  The last three list elements contain the additional
slots for an @f[annotated-binop].